package com.pi.stroop.service;

import java.text.MessageFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.validation.constraints.NotNull;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import com.pi.base.contants.WxConstants;
import com.pi.base.dto.file.transfer.StreamFileTransferForm;
import com.pi.base.dto.result.respcode.error.ErrorServer;
import com.pi.base.dto.result.respcode.stroop.StroopResp;
import com.pi.base.enumerate.file.FileSource;
import com.pi.base.enumerate.record.RecordState;
import com.pi.base.enumerate.redis.RedisCacheEnum;
import com.pi.base.exception.ServiceException;
import com.pi.base.util.bean.ObjectTool;
import com.pi.base.util.cache.RedisUtil;
import com.pi.base.util.http.UrlBuilder;
import com.pi.base.util.http.v2.HttpPostUtil;
import com.pi.base.util.http.v2.param.HttpRequestParam;
import com.pi.base.util.transfer.windows.FileUtil;
import com.pi.config.model.PartnerAppConfig;
import com.pi.config.service.ConfigService;
import com.pi.stroop.dao.entity.StroopInvitationEntity;
import com.pi.stroop.dao.mapper.StroopInvitationMapper;
import com.pi.stroop.dao.param.StroopInvitationParam;
import com.pi.stroop.model.wx.WxAccessTokenInfo;
import com.pi.uc.dao.entity.UcUserConfigEntity;
import com.pi.uc.dao.entity.UcUserEntity;
import com.pi.uc.enumerate.UserConfigType;
import com.pi.uc.service.UcUserConfigService;
import com.pi.uc.service.UcUserService;

@Validated
@Service
public class StroopInvitationService {
  @Autowired
  private StroopInvitationMapper invitationMapper;
  @Autowired
  private UcUserService userService;
  @Autowired
  private ConfigService configService;
  @Autowired
  private UcUserConfigService userConfigService;
  @Value("${server.ftp.host}")
  private String ftpHost;
  @Value("${server.ftp.password}")
  private String ftpPass;
  @Value("${server.ftp.user}")
  private String ftpUserName;
  @Value("${server.ftp.parentFolder}")
  private String ftpParentFolder;
  @Value("${server.ftp.root}")
  private String ftpRoot;
  @Value("${server.ftp.url}")
  private String ftpUrl; 
  public void share(
      @NotNull(message="STROOP.INVITER_ID_EMPTY") Long inviterId, 
      @NotNull(message="STROOP.USER_ID_EMPTY") Long loginUserId){
    List<StroopInvitationEntity> list = getInvitationInfo(loginUserId);
    StroopInvitationEntity matched = getExistInvite(loginUserId, inviterId, list);
    if(null == matched){
      StroopInvitationEntity invitationInfo = new StroopInvitationEntity();
      invitationInfo.setInviterId(inviterId);
      invitationInfo.setUserId(loginUserId);
      invitationInfo.setUserPv(1);
      if(null == list || list.isEmpty()){        
        invitationInfo.setInviteState(RecordState.STATE_NORMAL.getCode());
      }else{
        invitationInfo.setInviteState(RecordState.STATE_DELETE.getCode());
      }
      invitationMapper.insert(invitationInfo);
    }else{
      matched.setUserPv(matched.getUserPv() + 1);
      invitationMapper.updateById(matched);
    }
  }
  
  public String getShareQrcode(
      @NotNull(message="STROOP.USER_ID_EMPTY") Long loginUserId) 
          throws Exception{
    UcUserEntity userEntity = userService.queryUserInfo(loginUserId);
    //查询是否已有二维码缓存
    UcUserConfigEntity userConfig = userConfigService.queryUserConfig(
        loginUserId, UserConfigType.STROOP_INVITATION_QRCODE);
    if(null != userConfig){
      return userConfig.getConfigValue();
    }
    //查询app配置
    PartnerAppConfig config = configService.queryPartnerAppConfig(userEntity.getSourceId());
    String accessToken = getWxAccessToken(config);

    String url = getWxMiniQrcode(accessToken, userEntity.getSourceId(), loginUserId);
    userConfigService.addUserConfig(loginUserId, UserConfigType.STROOP_INVITATION_QRCODE, url);
    return url;
  }
  
  public List<StroopInvitationEntity> queryUserInvitation(
      @NotNull(message="UC_USER.USER_ID_EMPTY") Long userId){
    StroopInvitationParam param = new StroopInvitationParam();
    param.setInviterId(userId);
    return invitationMapper.findList(param);
  }
  
  public StroopInvitationEntity queryUserInviter(
      @NotNull(message="STROOP_INVITATION.USER_ID_IS_EMPTY")Long userId){
    StroopInvitationParam param = new StroopInvitationParam();
    param.setUserId(userId);
    param.setInviteState(RecordState.STATE_NORMAL.getCode());
    List<StroopInvitationEntity> list = invitationMapper.findList(param);
    return ObjectTool.getOne(list);
  }
  
  private List<StroopInvitationEntity> getInvitationInfo(Long loginUserId){
    StroopInvitationParam param = new StroopInvitationParam();
    param.setUserId(loginUserId);
    List<StroopInvitationEntity> list = invitationMapper.findList(param);
    return list;
  }
  private StroopInvitationEntity getExistInvite(Long loginUserId, Long inviterId, 
      List<StroopInvitationEntity> list){
    if(null == list || list.isEmpty()){
      return null;
    }
    for(StroopInvitationEntity invite:list){      
      if(invite.getUserId().intValue() == loginUserId 
          && invite.getInviterId().intValue() == inviterId){
        return invite;
      }
    }
    return null;
  }
  
  private String getWxAccessToken(PartnerAppConfig config) throws Exception{
    String token = RedisUtil.get(RedisCacheEnum.WX_ACCESS_TOKEN);
    if(StringUtils.isBlank(token)){
      WxAccessTokenInfo tokenInfo = HttpPostUtil.getRestResult(
          MessageFormat.format(
              WxConstants.WCHAT_APP_TOKEN_URL, 
              config.getAppId(), 
              config.getAppSecret()), 
          null, WxAccessTokenInfo.class);
      checkWxAccessTokenInfo(tokenInfo);
      token = tokenInfo.getAccess_token();
    }
    return token;
  }
  
  private String getWxMiniQrcode(String token, long sourceId, long loginUserId) throws Exception{
    Map<String, Object> paramMap = new HashMap<String,Object>();
    paramMap.put("scene", "QR," + loginUserId);
    paramMap.put("page", "pages/test/test" );
    paramMap.put("width", "430");
    
    HttpRequestParam requestParam = new HttpRequestParam();
    requestParam.addJsonHeader();
    requestParam.setParamMap(paramMap);
    requestParam.setUrl(MessageFormat.format(
        WxConstants.WCHAT_MINI_QRCODE_URL,
        token));
    byte[] is = HttpPostUtil.getRequestByte(requestParam);
    if(null == is){
      throw new ServiceException(
          ErrorServer.REQUEST_FILE_NOT_EXIST.getTag(),
          ErrorServer.REQUEST_FILE_NOT_EXIST.getErrorCode());
    }
    
    StreamFileTransferForm<byte[]> streamForm = new StreamFileTransferForm<>();
    streamForm.setFileSource(FileSource.STROOP_USER_QROCDE);
    streamForm.setFtpParentFolder(ftpParentFolder);
    streamForm.setFtpRoot(ftpRoot);
    streamForm.setIn(is);
    streamForm.setSourceId(sourceId);
    streamForm.setUserId(loginUserId);
    String fileKey = FileUtil.transferToLocal(streamForm);
    return new UrlBuilder()
        .build(ftpUrl)
        .build(fileKey).toString();
  }
  
  private void checkWxAccessTokenInfo(WxAccessTokenInfo tokenInfo){
    if(null == tokenInfo || StringUtils.isBlank(tokenInfo.getAccess_token())){
      throw new ServiceException(
          StroopResp.RESP_WX_TOKEN_FAILED.getTag(),
          StroopResp.RESP_WX_TOKEN_FAILED.getErrorCode());
    }
  }
}
